
package com.gl.glcourses.services.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.naming.directory.Attributes;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.flex.remoting.RemotingDestination;
import org.springframework.ldap.NamingException;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.gl.glcourses.mail.impl.SendUsuarioSinOficina;
import com.gl.glcourses.repository.IOficinaRepository;
import com.gl.glcourses.repository.IStaticRepository;
import com.gl.glcourses.repository.IUsuarioRepository;
import com.gl.glcourses.services.IUsuarioServices;
import com.gl.glcourses.vos.Confirmacion;
import com.gl.glcourses.vos.Oficina;
import com.gl.glcourses.vos.StaticHorasOficina;
import com.gl.glcourses.vos.TipoUsuario;
import com.gl.glcourses.vos.Usuario;

@Service
@RemotingDestination(channels = { "my-amf" })
@Transactional
public class UsuarioServices implements IUsuarioServices {

	@Autowired
	IUsuarioRepository<Usuario> repoUser;

	@Autowired
	IOficinaRepository<Oficina> repoOffice;
	
	@Autowired
	IStaticRepository<Object> repoStatic;

	@Autowired
	LdapTemplate ldapTemplate;
	
	@Autowired
	SendUsuarioSinOficina sendUsuarioSinOficina;
	
	@Override
	public void updateUsuario(Usuario usuario) throws Exception {
		
		repoUser.saveUpdate(usuario);
	}
	@SuppressWarnings("unchecked")
	public Confirmacion updateNewUsers() {
		AndFilter andFilter = new AndFilter();
		andFilter.and(new EqualsFilter("objectclass", "person"));

		List<Confirmacion> listUserLDAP = ldapTemplate.search(
				"OU=EZE1,OU=Allusers", andFilter.encode(),
				new getAllUserMapper());

		System.out.println("usuarios actualizados!!");
	
		return (Confirmacion) listUserLDAP.get(0);
	}

	@SuppressWarnings("unchecked")
	public Usuario buscarUsuario(String nombre) throws Exception {

		Usuario usuarioBuscado = repoUser.findUsuario(nombre);

		if (usuarioBuscado == null) {
			AndFilter andFilter = new AndFilter();
			andFilter.and(new EqualsFilter("objectclass", "person"));
			andFilter.and(new EqualsFilter("sAMAccountName", nombre));

			System.out.println("LDAP Query " + andFilter.encode());
			List<Usuario> list = ldapTemplate.search("OU=Allusers",
					andFilter.encode(), new UsuarioAttributesMapper());
			usuarioBuscado = (Usuario) list.get(0);
			usuarioBuscado.setRol("USUARIO");
			usuarioBuscado = repoUser.saveUsuarioAndUpdate(usuarioBuscado);
		}
		return usuarioBuscado;
	}
	
	private Usuario setRolPM(String nombre, boolean isManager) throws Exception{
		
		Usuario usuarioBuscado=this.buscarUsuario(nombre);

		usuarioBuscado.setRol("PM");
		usuarioBuscado.setTipoUsuario(TipoUsuario.PM);
		
		usuarioBuscado = repoUser.saveUsuarioAndUpdate(usuarioBuscado);
		return usuarioBuscado;
	}

	public List<Usuario> buscarUsuariosPM() {
		return repoUser.buscarTipodeUsuarios(TipoUsuario.PM);
	}

	public List<Usuario> buscarUsuariosxOficina(Oficina oficina) {
		if(oficina==null){
			return repoUser.busarUsuariosSinOficinas();
		}
		return repoUser.buscarUsuariosXOficinas(oficina);

	}
	
	public List<Usuario> buscarUsuariosSimplexOficina(Oficina oficina) {
		return repoUser.buscarUsuariosSimplesXOficinas(oficina);

	}

	public List<Usuario> listarUsuarios() {
		return repoUser.buscarUsuarios();
	}
	
	
	// SENT MAILS
	
	public void notificacionUsuariosSinOficina()
	{
		List<Usuario>usuarios = this.listarUsuarios();

		for(Usuario usuario : usuarios)
		{
			if(usuario.getOficina() == null)
			{
				SimpleMailMessage msg = new SimpleMailMessage();
				Map<Object, Object> hTemplateVariables = new HashMap<Object, Object>();
				msg.setSubject("Usuarios sin oficina");
				sendUsuarioSinOficina.send(msg, hTemplateVariables);
				return;
			}
		}
	}
	
	
	// PRIVATE METHODS FOR USUARIOSERVICES
	
	private String findUserByName(String name) {

		AndFilter andFilter = new AndFilter();
		andFilter.and(new EqualsFilter("objectclass", "person"));
		andFilter.and(new EqualsFilter("cn", name));

		@SuppressWarnings("rawtypes")
		List list = ldapTemplate.search("OU=EZE1,OU=Allusers",
				andFilter.encode(), new getUserMapper());
		Usuario user = (Usuario) list.get(0);

		if(user==null)
		{
			list = ldapTemplate.search("OU=Users,OU=BOM,OU=Allusers",
					andFilter.encode(), new getUserMapper());
			user = (Usuario) list.get(0);
			return user.getNombre();
		}
		return user.getNombre();
	}
	
	private String formatMail(String mail) {
		
		String formatMail = mail.substring(mail.indexOf(':') + 2);
		
		return formatMail;
	}
	
	private String formatName(String name) {
		
		String formatName = name.substring(0, name.indexOf('@')).toLowerCase();
		
		return formatName;
	}
	
	public List<Usuario> buscarUsuariosACargo(Usuario usuario) {
		return repoUser.buscarUsuariosACargo(usuario);
	}
	
	private String formatNameManager(String nameManager) {
		
		String formatNameManager = nameManager.substring(
				nameManager.indexOf('=') + 1,
				nameManager.indexOf(','));
		
		return formatNameManager;		
	}
	
	private Oficina getOficina(String nombreOficina) {
	
		if(nombreOficina==null)
		{
			return null;
		}	
		String nameOffice = nombreOficina.substring(nombreOficina.indexOf(':') + 2);	
		
		Oficina office = (Oficina) repoOffice.findOficina("nombre",nameOffice);
		
		if (office == null) {
			try {
				office = new Oficina();
				office.setNombre(nameOffice);
				office = repoOffice.saveUpdate(office);
				
				StaticHorasOficina staticHorasOficina = new StaticHorasOficina();
				staticHorasOficina.setOficina(office);
				staticHorasOficina.setCantHoras((double) 0);
				staticHorasOficina.setCantCursos(0);
				staticHorasOficina.setCantParticipantes(0);
				repoStatic.saveStatic(staticHorasOficina);
				
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return office;
		
	}

	// PRIVATE CLASSES FOR LDAP SEARCH

	private class getUserMapper implements AttributesMapper {
		public Object mapFromAttributes(Attributes attrs)
				throws NamingException {
			Usuario user = new Usuario();

			String mail = attrs.get("mail").toString();
			mail = mail.substring(mail.indexOf(':') + 2);

			String nombreUsuario = mail.substring(0, mail.indexOf('@'))
					.toLowerCase();

			user.setNombre(nombreUsuario);

			return user;
		}
	}

	private class UsuarioAttributesMapper implements AttributesMapper {

		public Object mapFromAttributes(Attributes attrs)
				throws NamingException {
			Usuario usuario = new Usuario();
			
			Oficina oficina = new Oficina();

			String mail = formatMail(attrs.get("mail").toString());

			String nombreUsuario = formatName(mail);

			String nombreManager;
			if(attrs.get("manager")==null)
			{
				nombreManager = nombreUsuario;
			}
			else
			{
				nombreManager = formatNameManager(attrs.get("manager").toString());
				nombreManager = findUserByName(nombreManager);
			}

			try {
				if (nombreManager.equals(nombreUsuario)) {
					usuario.setManager(null);
				} else {
					usuario.setManager(setRolPM(nombreManager, true));
				}
				
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
			if(attrs.get("physicalDeliveryOfficeName")==null)
			{
				usuario.setOficina(null);
				
			}
			else
			{		
				oficina=getOficina(attrs.get("physicalDeliveryOfficeName").toString());
				usuario.setOficina(oficina);
			}
			
			usuario.setTipoUsuario(TipoUsuario.USUARIO);
			usuario.setNombre(nombreUsuario);
			usuario.setMail(mail);
			return usuario;
		}
	}

	private class getAllUserMapper implements AttributesMapper {
		public Object mapFromAttributes(Attributes attrs)
				throws NamingException {

			if (attrs.get("mail") != null) {
				String mail = attrs.get("mail").toString();
				mail = mail.substring(mail.indexOf(':') + 2);

				String nombreUsuario = mail.substring(0, mail.indexOf('@'))
						.toLowerCase();

				try {
					buscarUsuario(nombreUsuario);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			Confirmacion confirmacion = new Confirmacion();
			confirmacion.setEstado(true);
			return confirmacion;
		}
	}
}
